package elitequant.gui;

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import javax.imageio.ImageIO;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.UIManager;

import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.FormLayout;

import elitequant.LiveEngine.Config;
import elitequant.event.ClientMq;
import elitequant.event.Event;
import elitequant.event.EventHandler;
import elitequant.event.EventType;
import elitequant.event.GeneralEvent;
import elitequant.event.LiveEventEngine;
import elitequant.strategy.StrategyBase;
import elitequant.util.OsInfo;

/**
 * Main window
 * 
 */
public class MainWindow extends JFrame implements EventHandler {

    private static final long serialVersionUID = -7179627727830984434L;

    private LiveEventEngine eventsEngine;

    private ClientMq clientMq;

    private List<Class<StrategyBase>> strategieClazzs;

    private Config config;

    private JLabel statusLabel;

    private JTextArea messageWindow;
    
    private OrderWindow orderWindow;

    private FillWindow fillWindow;

    /* ------------------place order widget------------------------- */
    private JTextField txSymbol;
    
    private JComboBox<String> comOrderType;
    
    private JComboBox<String> comOrderFlag;
    
    private JTextField txOrderPrice;

    private JTextField txOrderQuantity;

    private Timer updateStatusTimer;
    
    private JSplitPane splitPane1;
    private JSplitPane splitPane2;
    private JSplitPane splitPane3;

    public MainWindow(Config config) {
        
        this.config = config;

        // event engine
        eventsEngine = new LiveEventEngine();

        // client mq
        clientMq = new ClientMq(eventsEngine);

        // set up gui windows
        initUi();

        // read strategies
        strategieClazzs = StrategyBase.strategyClassList();

        // wire up event handlers

        updateStatusTimer = new Timer("updateStatusTimer");
        updateStatusTimer.schedule(new UpdateStatusTimerTask(), 1000, 10000);

        // wire up event handlers
        registerEvent();

        // start
        eventsEngine.start();
        clientMq.start();
        clientMq.subscribe(config.getTickers());
    }

    private void initUi() {

        try {

            /*
             * Set then skin
             * 
             * javax.swing.plaf.metal.MetalLookAndFeel
             * javax.swing.plaf.nimbus.NimbusLookAndFeel
             * com.sun.java.swing.plaf.motif.MotifLookAndFeel
             * com.sun.java.swing.plaf.windows.WindowsLookAndFeel
             * com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel
             * com.jgoodies.looks.windows.WindowsLookAndFeel
             */
            UIManager.setLookAndFeel(
                    "com.jgoodies.looks.windows.WindowsLookAndFeel");
        } catch (Exception e) {
            // ignore
        }
        
        setTitle("EliteQuant_Java");
        
        try {
            setIconImage(ImageIO.read(new File("logo.png")));
        } catch (Exception e) {
            // ignore
        }

        setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
        addWindowListener(new WindowAdapter() {

            @Override
            public void windowClosing(WindowEvent e) {

                MainWindow.this.close();
            }
        });
        setSize(Toolkit.getDefaultToolkit().getScreenSize());
        setExtendedState(JFrame.MAXIMIZED_BOTH);
        setResizable(true);

        initMenu();
        initStatusBar();
        initCentralArea();
        setVisible(true);

        // must after setVisible to reset split panel
        splitPane1.setDividerLocation(0.7);
        splitPane2.setDividerLocation(0.6);
        splitPane3.setDividerLocation(0.85);
    }

    private void initCentralArea() {
        splitPane1 = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
        add(BorderLayout.CENTER, splitPane1);

        splitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        splitPane1.add(splitPane2);
        
        // -------------------------------- Top Left ------------------------------------------
        MarketWindow marketWindow = new MarketWindow(eventsEngine,
                config.getTickers());
        splitPane2.add(marketWindow);
        
        //-------------------------------- Top right ------------------------------------------
        txSymbol = new JTextField();
        comOrderType = new JComboBox<String>(new String[] {"MKT", "LMT"});
        comOrderFlag = new JComboBox<String>(new String[] {"OPEN","CLOSE","CLOSE_TODAY","CLOSE_YESTERDAY"});
        txOrderPrice = new JTextField();
        txOrderQuantity = new JTextField();

        JButton btnOrder = new JButton("Place Order");
        btnOrder.addActionListener(new PlaceOrderAction());
        
        JPanel pane = new JPanel();
        pane.setLayout(new FlowLayout(FlowLayout.CENTER));
        splitPane2.add(pane);
        JPanel contentPane = new JPanel();
        pane.add(contentPane);

        String columns = "pref, 4dlu, 150dlu, 4dlu, pref";
        String rows = "pref, 15dlu, pref, 15dlu, pref, 15dlu, pref, 15dlu, pref, 15dlu, pref";
        FormLayout layout = new FormLayout(columns, rows);

        contentPane.setLayout(layout);

        CellConstraints cc = new CellConstraints();
        contentPane.add(new JLabel("Symbol"), cc.xy(1, 1));
        contentPane.add(new JLabel("OrderType"), cc.xy(1, 3));
        contentPane.add(new JLabel("OrderFlag"), cc.xy(1, 5));
        contentPane.add(new JLabel("OrderPrice"), cc.xy(1, 7));
        contentPane.add(new JLabel("OrderQuantity"), cc.xy(1, 9));
        
        contentPane.add(txSymbol, cc.xy(3, 1));
        contentPane.add(comOrderType, cc.xy(3, 3));
        contentPane.add(comOrderFlag, cc.xy(3, 5));
        contentPane.add(txOrderPrice, cc.xy(3, 7));
        contentPane.add(txOrderQuantity, cc.xy(3, 9));
        
        contentPane.add(btnOrder, cc.xy(3, 11));

        // -------------------------------- bottom Left ------------------------------------------
        splitPane3 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
        splitPane1.add(splitPane3);

        JTabbedPane tabbedPane = new JTabbedPane();
        splitPane3.add(tabbedPane);

        messageWindow = new JTextArea();
        messageWindow.setEditable(false);
        tabbedPane.addTab("Message", messageWindow);
        orderWindow = new OrderWindow(eventsEngine, clientMq);
        tabbedPane.addTab("Order", orderWindow);
        fillWindow = new FillWindow(eventsEngine);
        tabbedPane.addTab("Fill", fillWindow);


       // -------------------------------- bottom right ------------------------------------------
        splitPane3.add(new JPanel());
    }


    private void initStatusBar() {
        statusLabel = new JLabel();
        add(BorderLayout.SOUTH, statusLabel);
        updateStatusBar();
    }

    private void initMenu() {
        JMenuBar menubar = new JMenuBar();

        JMenu sysMenu = new JMenu("File");

        // open folder
        JMenuItem folderMenu = new JMenuItem("Folder", 'F');
        folderMenu.addActionListener(new FolderAction());
        sysMenu.add(folderMenu);

        sysMenu.addSeparator();

        // sys|exit
        JMenuItem exitMenu = new JMenuItem("Exit", 'E');
        exitMenu.addActionListener(new ExitAction());
        sysMenu.add(exitMenu);

        menubar.add(sysMenu);
        setJMenuBar(menubar);
    }

    private void registerEvent() {
        eventsEngine.registerHandler(EventType.GENERAL, this);
    }

    @Override
    public void handle(Event event) {
        if (event.getClass().isAssignableFrom(GeneralEvent.class)) {
            addMessage((GeneralEvent) event);
        }

    }

    private void placeOrder() {

        String s = txSymbol.getText();
        String t = (String)comOrderType.getSelectedItem();
        String f = (String)comOrderFlag.getSelectedItem();
        String p = txOrderPrice.getText();
        String q = txOrderQuantity.getText();
        
        String msg = null;
        if("MKT".equals(t)) {
            msg = String.format("o|MKT|%s|%s", s, q);
        }
        else {
            msg = String.format("o|MKT|%s|%s|%s|%s", s, q, p, f);
        }

        this.clientMq.send(msg);
    }

    private void addMessage(GeneralEvent generalEvent) {
        messageWindow.append(generalEvent.content + "\n");
    }

    private void updateStatusBar() {
        String message = String.format("CPU Usage: %s%% Memory Usage: %s%%",
                OsInfo.getCPURate(), OsInfo.getMemoryRate());
        statusLabel.setText(message);
    }

    public void close() {

        int exi = JOptionPane.showConfirmDialog(null, "Do you want to quit the program？", "Friendly reminder",
                JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
        if (exi == JOptionPane.YES_OPTION) {
            eventsEngine.stop();
            clientMq.stop();
            System.exit(0);
        }
    }

    private class FolderAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            // TODO:
        }
    }

    private class ExitAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            MainWindow.this.close();
        }
    }

    private class PlaceOrderAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            MainWindow.this.placeOrder();
        }
    }

    class UpdateStatusTimerTask extends TimerTask {

        @Override
        public void run() {
            MainWindow.this.updateStatusBar();

        }

    }
    
    public void setVisible(boolean b) {
        super.setVisible(b);
        
        // waiting for ui layout
        try {
            Thread.sleep(500);
        } catch (Exception e) {
            // ignore
        }
    }

}
